package com.dragon.modules.yuegou.client.wechat_mini.security;

import com.dragon.modules.yuegou.client.wechat_mini.common.BaseResponse;
import com.dragon.modules.yuegou.client.wechat_mini.model.AccessToken;

import java.util.function.Function;

/**
 * 接口调用凭证服务
 * 
 * @author liuwu
 *
 */
public interface AccessTokenService {

	/**
	 * 获取有效的AccessToken<br>
	 * 请注意：实现方应该缓存有效的AccessToken，不要每次调用都去获取新的
	 * 
	 * @return AccessToken
	 */
	AccessToken getAccessToken();

	/**
	 * 刷新AccessToken
	 * 
	 * @return 刷新后的AccessToken
	 */
	AccessToken refreshAccessToken();

	/**
	 * 执行某个接口调用函数(function),使用映射函数(mapper)转化结果<br>
	 * 如果执行函数的返回结果表明AccessToken已经失效,则自动刷新AccessToken然后重试.
	 * 
	 * @param function 接口函数,输入参数是AccessToken字符串,返回结果是继承BaseResponse的对象
	 * @param mapper   转化函数
	 * @return 执行函数,转化后的结果
	 * @throws
	 */
	default <T, R extends BaseResponse> T executeAutoRetry(Function<String, R> function, Function<R, T> mapper) {
		AccessToken accessToken = getAccessToken();
		String token = accessToken.getValue();
		R response = function.apply(token);
		if (response.isAccessTokenExpired()) {
			AccessToken refreshedAccessToken = refreshAccessToken();
			String newToken = refreshedAccessToken.getValue();
			R retriedResponse = function.apply(newToken);
			retriedResponse.check();
			return mapper.apply(retriedResponse);
		}
		response.check();
		return mapper.apply(response);
	}

	/**
	 * 执行某个接口调用函数(function),不需要返回结果<br>
	 * 如果执行函数的返回结果表明AccessToken已经失效,则自动刷新AccessToken然后重试.
	 * 
	 * @param function 函数
	 * @see #executeAutoRetry(Function, Function)
	 */
	default void executeAutoRetry(Function<String, BaseResponse> function) {
		executeAutoRetry(function, BaseResponse::isOk);
	}
}
